/*********************************************************************NVMH3****
*******************************************************************************
$Revision: #4 $

Copyright NVIDIA Corporation 2008
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED
*AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS
BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES
WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY
LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

Comments:
	HLSL noise implementation for vertex programs.
	1D, 2D, and 3D noise calls are supported.

	float vertex_noise(float  v, const uniform float4 pg[FULLSIZE])
	float vertex_noise(float2 v, const uniform float4 pg[FULLSIZE])
	float vertex_noise(float3 v, const uniform float4 pg[FULLSIZE])

	A suitable table of values for "pg" will also be declared if one is not provided
		(see section below on "vnoise-table.fxh")

	This is based on Ken Perlins original code:
	http://mrl.nyu.edu/~perlin/doc/oscar.html
	& Thanks to Simon Green - KB

	It combines the permutation and gradient tables into one array of
		float4's to conserve constant memory.
	The table is duplicated twice to avoid modulo operations.

Notes:
	Should really use separate tables for 1


To learn more about shading, shaders, and to bounce ideas off other shader
    authors and users, visit the NVIDIA Shader Library Forums at:

    http://developer.nvidia.com/forums/

*******************************************************************************
******************************************************************************/



#ifndef _H_VERTEX_NOISE
#define _H_VERTEX_NOISE

//
// The following include directive sources-in a file that contains definitions for the macros
//	BSIZE, FULLSIZE, and NOISEFRAC, and a constant declaration for a table of perturbation and gradient
//	values. This table was generated by the companion perl program "vnoise_init.pl"
//	This table, calleb NTab, is an array of float4's: float4 NTab[FULLSIZE]
//
// If you want to supply a different table, run vnoise_init.pl with a different seed value and/or
//	table size, and include its results BEFORE including the current file (vertexnoise.fxh)
//
#ifndef NOISEFRAC
#include <include\\vnoise-table.fxh>
#endif /* NOISEFRAC */

#define NO_NEG_HACK 10000.0f

///////////// functions 

// this is the smoothstep function f(t) = 3t^2 - 2t^3, without the normalization
float3 s_curve(float3 t) { return t*t*( float3(3,3,3) - float3(2,2,2)*t); }
float2 s_curve(float2 t) { return t*t*( float2(3,3) - float2(2,2)*t); }
float  s_curve(float  t) { return t*t*(3.0-2.0*t); }

// 3D version
float vertex_noise(float3 v,
			const uniform float4 pg[FULLSIZE])
{
    v = v + float3(NO_NEG_HACK, NO_NEG_HACK, NO_NEG_HACK);   // hack to avoid negative numbers
    float3 i = frac(v * NOISEFRAC) * BSIZE;   // index between 0 and BSIZE-1
    float3 f = frac(v);            // fractional position
    // lookup in permutation table
    float2 p;
    p.x = pg[ i[0]     ].w;
    p.y = pg[ i[0] + 1 ].w;
    p = p + i[1];
    float4 b;
    b.x = pg[ p[0] ].w;
    b.y = pg[ p[1] ].w;
    b.z = pg[ p[0] + 1 ].w;
    b.w = pg[ p[1] + 1 ].w;
    b = b + i[2];
    // compute dot products between gradients and vectors
    float4 r;
    r[0] = dot( pg[ b[0] ].xyz, f );
    r[1] = dot( pg[ b[1] ].xyz, f - float3(1.0f, 0.0f, 0.0f) );
    r[2] = dot( pg[ b[2] ].xyz, f - float3(0.0f, 1.0f, 0.0f) );
    r[3] = dot( pg[ b[3] ].xyz, f - float3(1.0f, 1.0f, 0.0f) );
    float4 r1;
    r1[0] = dot( pg[ b[0] + 1 ].xyz, f - float3(0.0f, 0.0f, 1.0f) );
    r1[1] = dot( pg[ b[1] + 1 ].xyz, f - float3(1.0f, 0.0f, 1.0f) );
    r1[2] = dot( pg[ b[2] + 1 ].xyz, f - float3(0.0f, 1.0f, 1.0f) );
    r1[3] = dot( pg[ b[3] + 1 ].xyz, f - float3(1.0f, 1.0f, 1.0f) );
    // interpolate
    f = s_curve(f);
    r = lerp( r, r1, f[2] );
    r = lerp( r.xyyy, r.zwww, f[1] );
    return lerp( r.x, r.y, f[0] );
}

// 2D version
float vertex_noise(float2 v,
			const uniform float4 pg[FULLSIZE])
{
    v = v + float2(NO_NEG_HACK, NO_NEG_HACK);
    float2 i = frac(v * NOISEFRAC) * BSIZE;   // index between 0 and BSIZE-1
    float2 f = frac(v);            // fractional position
    // lookup in permutation table
    float2 p;
    p[0] = pg[ i[0]   ].w;
    p[1] = pg[ i[0]+1 ].w;
    p = p + i[1];
    // compute dot products between gradients and vectors
    float4 r;
    r[0] = dot( pg[ p[0] ].xy,   f);
    r[1] = dot( pg[ p[1] ].xy,   f - float2(1.0f, 0.0f) );
    r[2] = dot( pg[ p[0]+1 ].xy, f - float2(0.0f, 1.0f) );
    r[3] = dot( pg[ p[1]+1 ].xy, f - float2(1.0f, 1.0f) );
    // interpolate
    f = s_curve(f);
    r = lerp( r.xyyy, r.zwww, f[1] );
    return lerp( r.x, r.y, f[0] );
}

// 1D version
float vertex_noise(float v,
		const uniform float4 pg[FULLSIZE])
{
    v = v + NO_NEG_HACK;
    float i = frac(v * NOISEFRAC) * BSIZE;   // index between 0 and BSIZE-1
    float f = frac(v);            // fractional position
    // compute dot products between gradients and vectors
    float2 r;
    r[0] = pg[i].x * f;
    r[1] = pg[i + 1].x * (f - 1.0f);
    // interpolate
    f = s_curve(f);
    return lerp( r[0], r[1], f);
}

#endif /* _H_VERTEX_NOISE */

///////////////////////////////////////////////////////////////// eof //
